﻿using MyCommon.LogHelper;
using Serilog;
using Serilog.Context;
using Serilog.Events;
using Serilog.Filters;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MySerilog.Extensions
{
    public static class LoggerConfigurationExtensions
    {
        /// <summary>
        /// 日志输出到控制台
        /// </summary>
        /// <param name="loggerConfiguration"></param>
        /// <returns></returns>
        public static LoggerConfiguration WriteToConsole(this LoggerConfiguration loggerConfiguration) {
            // 输出普通日志
            loggerConfiguration = loggerConfiguration.WriteTo.Logger(lg => lg.FileRemoveSqlLog().WriteTo.Console());

            //输出SQL
            loggerConfiguration = loggerConfiguration.WriteTo.Logger(lg=>lg.FilterSqlLog().Filter.ByIncludingOnly(Matching.WithProperty<bool>(LogContextStatic.SqlOutToConsole,s=>s)).WriteTo.Console());

            return loggerConfiguration;
        }

        public static LoggerConfiguration WriteToFile(this LoggerConfiguration loggerConfiguration) {
            // 输出SQL
            loggerConfiguration = loggerConfiguration.WriteTo.Logger(
                  lg => lg.FilterSqlLog().Filter.ByIncludingOnly(Matching.WithProperty<bool>(LogContextStatic.SqlOutToFile, s => s))
                  .WriteTo.Async(s => s.File(LogContextStatic.Combine(LogContextStatic.AopSql, @"AopSql.txt"), 
                      rollingInterval: RollingInterval.Day,outputTemplate: LogContextStatic.FileMessageTemplate, retainedFileCountLimit: 31)));
            
            // 输出普通日志
            loggerConfiguration = loggerConfiguration.WriteTo.Logger(
                lg=>lg.FileRemoveSqlLog().WriteTo.Async(s=>s.File(LogContextStatic.Combine(LogContextStatic.BasePathLogs,@"Log.txt"),
                rollingInterval: RollingInterval.Day,outputTemplate:LogContextStatic.FileMessageTemplate,retainedFileCountLimit: 31)));

            
            return loggerConfiguration;
        }
        /// <summary>
        /// 不记录SQL的日志
        /// </summary>
        /// <param name="loggerConfiguration"></param>
        /// <returns></returns>
        public static LoggerConfiguration FileRemoveSqlLog(this LoggerConfiguration loggerConfiguration) { 
            loggerConfiguration = loggerConfiguration.Filter.ByIncludingOnly(WithProperty<string>(LogContextStatic.LogSource,s=>!LogContextStatic.AopSql.Equals(s)));
            return loggerConfiguration;
        }
        /// <summary>
        /// 只记录SQL的日志
        /// </summary>
        /// <param name="loggerConfiguration"></param>
        /// <returns></returns>
        public static LoggerConfiguration FilterSqlLog(this LoggerConfiguration loggerConfiguration) { 
            loggerConfiguration = loggerConfiguration.Filter.ByIncludingOnly(Matching.WithProperty<string>(LogContextStatic.LogSource,s=>LogContextStatic.AopSql.Equals(s)));
            return loggerConfiguration;
        }

        public static Func<LogEvent, bool> WithProperty<T>(string propertyName, Func<T, bool> predicate) {
            // 如果不包含属性 也任务是true
            return e =>
            {
                if (!e.Properties.TryGetValue(propertyName, out var propertyValue)) return true;
                return propertyValue is ScalarValue { Value: T value } && predicate(value);
            };
        }

        public static bool WithProperty<T>(this LogEvent e, string key, Func<T, bool> predicate) {
            if (e.Properties.TryGetValue(key, out var propertyValue)) return false;
            return propertyValue is ScalarValue { Value:T value}&& predicate(value);
        }
        public static IEnumerable<LogEvent> FilterSqlLog(this IEnumerable<LogEvent> logs) { 
          return logs.Where(s=>s.WithProperty<string>(LogContextStatic.LogSource,q=>LogContextStatic.AopSql.Equals(q)))
                .Where(s => s.WithProperty<SugarActionType>(LogContextStatic.SugarActionType, q => !new[] { SugarActionType.UnKnown, SugarActionType.Query }.Contains(q)));
                
        }
    }
}
